package service

import (
	"fmt"
	"time"

	"github.com/dgrijalva/jwt-go"
	"gorm.io/gorm"

	"server/app/dao"
	"server/app/ecode"
	"server/app/middleware"
	"server/app/model"
	"server/pkg/utils"
)

type User struct {
	dao *dao.User
}

func NewUser() *User {
	return &User{
		dao: dao.NewUser(),
	}
}

const (
	MaxLoginTryCount = 5
)

func (u *User) Login(username, pwd, ua string) (string, error) {
	user, err := u.dao.FirstByUsername(username)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			err = ecode.ErrUserNotFound
		}
		return "", err
	}

	// 无论密码对错，如果尝试次数超过 5 次，则返回错误
	loginCount, err := u.dao.CountByUA(username, ua)
	if err != nil {
		return "", err
	}
	if loginCount >= MaxLoginTryCount {
		return "", fmt.Errorf("操作频繁，请稍后再试")
	}

	if user.Pwd != pwd {
		// 增加 ua 尝试次数
		loginCount++
		expire := time.Hour
		if loginCount >= MaxLoginTryCount {
			expire = time.Minute
		}
		if err = u.dao.UpdateCountByUA(username, ua, loginCount, expire); err != nil {
			return "", err
		}
		return "", fmt.Errorf("密码错误，已错误%d次，超过%d次就等待60s", loginCount, MaxLoginTryCount)
	}

	// 密码正确
	if err = u.dao.ResetCountByUA(username, ua); err != nil {
		return "", err
	}

	return u.createToken(user)
}

func (u *User) Register(username, pwd string) error {
	return u.dao.Transaction(func(tx *gorm.DB) error {
		user, err := u.dao.TxFirstByUsername(tx, username)
		if err != nil && err != gorm.ErrRecordNotFound {
			return err
		}
		if user != nil {
			return fmt.Errorf("用户名重复")
		}

		return u.dao.TxInsertUser(tx, &model.User{
			UserName: username,
			Pwd:      pwd,
		})
	})
}

// 登录以后签发jwt
func (u *User) createToken(user *model.User) (string, error) {
	return utils.NewJwt([]byte(middleware.SignKey)).CreateToken(jwt.MapClaims{
		"exp": time.Now().Add(7 * 24 * time.Hour).Unix(),
		"uid": user.ID,
	})
}
